 #include "Hero.h"
#include "Terrain.h"
#include <stdio.h>
#include <malloc.h>
#include <assert.h>

const int LEVELMAX=10;
void herInitstats(Hero *);

/***********************FONCTIONS DU HERO********************************************/

void herInit(Hero * pHero){

	pHero->name=(char *)malloc(20*sizeof(char));
	pHero->hpmax = 0;
	pHero->mpmax = 0;
	pHero->curhp = 0;
	pHero->curmp = 0;
	pHero->level = 0;
	pHero->curxp = 0;
	pHero->xpmax = 0;
	pHero->power = 0;
	pHero->intel = 0;
	pHero->x = 0;
	pHero->y = 0;
	pHero->mode = 0;
	pHero->direction = 0;
	pHero->target = NULL;
	pHero->terid = 1;
	pHero->tabspell = NULL; /*tableau de spell*/
	pHero->nbspell = 0; /*nombre de spell*/
   	pHero->cooldown = 0;
        pHero->attaque = 0; /*booleen qui enclenche l'attaque auto*/
	pHero->speed = 0;
	initialiserTabDyn(&pHero->targetlist);
	pHero->tabspell=NULL;

}

void herInitContiue(Hero * pHero){


	FILE * hSave;

	hSave = fopen("data/Database/SaveHero.db","r");
	if(hSave == NULL)
		hSave = fopen("../data/Database/SaveHero.db","r");
	assert(hSave!=NULL);

	fscanf(hSave,"#name = %s\n",pHero->name);
	fscanf(hSave,"#level = %d\n",&(pHero->level));
	fscanf(hSave,"#xp = %u\n",&(pHero->curxp));
	fscanf(hSave,"#posx = %d\n",&(pHero->x));
	fscanf(hSave,"#posy = %d\n",&(pHero->y));

	fscanf(hSave,"#terrain = %d\n",&(pHero->terid));

	fclose(hSave);

	herInitstats(pHero);
	pHero->mode=0;
	pHero->direction=2;
	pHero->target=NULL;
	pHero->cooldown=0;
	pHero->attaque=0;





}

void herInitNewGame(Hero * pHero){

	FILE * fsave;

	fsave = fopen("data/Database/SaveHero.db","w");
	if(fsave == NULL)
		fsave = fopen("../data/Database/SaveHero.db","w");
	assert(fsave!=NULL);

	fprintf(fsave,"#name = %s\n","Hero");
	fprintf(fsave,"#level = %d\n",1);
	fprintf(fsave,"#xp = %u\n",0);
	fprintf(fsave,"#posx = %d\n",5);
	fprintf(fsave,"#posy = %d\n",5);
	fprintf(fsave,"#terrain = %d\n",1);
	fclose(fsave);


}
void herInitstats(Hero * pHero){ /*initialisation des stats du hero en fonction de son level (fichier StatPerLevel.dat*/

	FILE * fStats;
	int i;
	int res;


	fStats = fopen("data/Database/StatPerLevel.dat","r");
	if(fStats == NULL)
	fStats = fopen("../data/Database/StatPerLevel.dat","r");
	assert(fStats!=NULL);

	fscanf(fStats,"Level Hpmax Mpmax Power Intel XpMax SPEED\n");

	do{

	res = fscanf(fStats,"%d %d %d %d %d %u %f\n",&i,&(pHero->hpmax),&(pHero->mpmax),&(pHero->power),
	&(pHero->intel),&(pHero->xpmax),&(pHero->speed));
	assert(res == 7);

	}while(i!=pHero->level && i<LEVELMAX); /*recherche de la bonne ligne dans statperlevel.dat*/

	fclose(fStats);
	pHero->cooldown = 0;
	pHero->curhp = pHero->hpmax;
	pHero->curmp = pHero->mpmax;
	if(pHero->tabspell!=NULL && pHero->nbspell != 0){
		spellFree(pHero->tabspell, pHero->nbspell);
		pHero->nbspell = 0;
	}
    	pHero->tabspell=spellInitContinue(&pHero->nbspell,pHero->level); /*initialisation du tableau de spell*/


}

void herSave(Hero * pHero){ /*sauvegarde le hero dans le fichier SaveHero.db*/

	FILE * fsave;

	fsave = fopen("data/Database/SaveHero.db","w");
	if(fsave == NULL)
	fsave = fopen("../data/Database/SaveHero.db","w");
	assert(fsave!=NULL);

	fprintf(fsave,"#name = %s\n",pHero->name);
	fprintf(fsave,"#level = %d\n",pHero->level);
	fprintf(fsave,"#xp = %u\n",pHero->curxp);
	fprintf(fsave,"#posx = %d\n",pHero->x);
	fprintf(fsave,"#posy = %d\n",pHero->y);
	fprintf(fsave,"#terrain = %d\n",pHero->terid);
	fclose(fsave);

}

void herFree(Hero * pHero){
	if(pHero->mode == 1){
        herDie(pHero);
	}
	else{
        herSave(pHero);
	}
	spellFree(pHero->tabspell,pHero->nbspell);
	free(pHero->name);
	testamentTabDyn(&pHero->targetlist);
	pHero=NULL;

}

void herGetPos(const Hero *pHero, int * x, int * y){

	*x=pHero->x;
	*y=pHero->y;
}

void heroHaut (Hero * pHero,Terrain * pTer){
	if(pHero->direction != 1){ /*si hero n'est pas dans la bonne direction, alors direction change*/
	pHero->direction=1;
	}
	else if(terTestPosition(pTer,pHero->x,pHero->y-1)){ /*si position est valide (pas de mur, pas de monstre*/
            terModif(pTer,pHero->x,pHero->y,0); /*on rend la case accessible*/
            pHero->y--; /*on bouge le hero*/
            terModif(pTer,pHero->x,pHero->y,1); /*on dis que la nouvelle case est occupée*/

    }
}
void heroBas (Hero * pHero,Terrain * pTer){
	if(pHero->direction != 3) {
	pHero->direction=3;
	}
	 else if(terTestPosition(pTer,pHero->x,pHero->y+1)) {
            terModif(pTer,pHero->x,pHero->y,0);
            pHero->y++;
            terModif(pTer,pHero->x,pHero->y,1);
    }
}

void heroGauche (Hero * pHero,Terrain * pTer){
	if(pHero->direction != 0){
	pHero->direction=0;
	}
	else if(terTestPosition(pTer,pHero->x-1,pHero->y)){
           terModif(pTer,pHero->x,pHero->y,0);
           pHero->x--;
           terModif(pTer,pHero->x,pHero->y,1);
    }
}

void heroDroite (Hero * pHero,Terrain * pTer){
	if(pHero->direction != 2){
	pHero->direction=2;
	}
	else if(terTestPosition(pTer,pHero->x+1,pHero->y)){
            terModif(pTer,pHero->x,pHero->y,0);
            pHero->x++;
            terModif(pTer,pHero->x,pHero->y,1);
    }
}

void herWinXp(Hero * pHero, unsigned int xpwin){ /*fonction qui fais gagner de l'experience au hero*/
    unsigned int surplus;
	if(pHero->level<LEVELMAX){
	   pHero->curxp+=xpwin;

	if(pHero->curxp>=pHero->xpmax){
	    surplus=pHero->curxp-pHero->xpmax; /*si level up, on garde le surplus d'xp en mémoire*/

	herLevelUp(pHero);
	herWinXp(pHero,surplus); /*on réinjecte le surplus d'xp dans le hero*/
        }
    }
}

void herLevelUp(Hero * pHero){
    pHero->level++;
    herInitstats(pHero);
    pHero->curxp=0;
}


void herTakeDamage(Hero * pHero,int damages){ /*fonction appelée pour infliger des degats au hero*/
    pHero->curhp-=damages;
    if(pHero->curhp<=0){
        pHero->curhp =0;
        pHero->mode=1; }

}
void herAttack(Hero * pHero){ /*fonction qui inflige des degats au monstre ciblé et qui renvoie si target vivante ou morte*/
    int damages;
    damages=pHero->power*0.5;
    monsterTakeDamage(pHero->target,damages);

}
int herGetlevel(const Hero * pHero){
    return pHero->level;
}
char * herGetname(const Hero * pHero){
    return pHero->name;
}
int herGetcurhp(const Hero * pHero){
    return pHero->curhp;
}
int herGethpmax(const Hero * pHero){
    return pHero->hpmax;
}
int herGetcurmp(const Hero * pHero){
    return pHero->curmp;
}
int herGetmpmax(const Hero * pHero){
    return pHero->mpmax;
}
int herGetcurxp(const Hero * pHero){
    return pHero->curxp;
}
int herGetxpmax(const Hero * pHero){
    return pHero->xpmax;
}

int herGetAttack(const Hero * pHero){
	return pHero->attaque;
}

Monster * herGetTarget(const Hero * pHero){

    return pHero->target;
}

void herAttackStart(Hero * pHero){

    pHero->attaque=1;
}
void herAttackEnd(Hero * pHero){

    pHero->attaque=0;
}
void herUseMana(Hero * pHero,int manaused){

    pHero->curmp -= manaused;
}
void herWinMana(Hero * pHero,int manawin){

   if(pHero->curmp + manawin > pHero->mpmax)
        pHero->curmp = pHero->mpmax;
   else
        pHero->curmp += manawin;
}
void herWinHp(Hero * pHero,int hpwin){

    if(pHero->curhp+hpwin > pHero->hpmax)
        pHero->curhp = pHero->hpmax;
    else
        pHero->curhp += hpwin;
}
float herGetCooldown(const Hero * pHero){
return pHero->cooldown;
}

int herGetMode(const Hero * pHero){
return pHero->mode;
}

TableauDynamique* herGetTargetList(Hero * pHer){
    return &(pHer->targetlist);
}

void herSetTarget(Hero * pHero,Monster * pMonster){


        pHero->target=pMonster;

}


void herDie(const Hero * pHero){ /*sauvegarde le hero dans le fichier SaveHero.db*/

	FILE * fsave;

	fsave = fopen("data/Database/SaveHero.db","w");
	if(fsave == NULL)
	fsave = fopen("../data/Database/SaveHero.db","w");
	assert(fsave!=NULL);

	fprintf(fsave,"#name = %s\n",pHero->name);
	fprintf(fsave,"#level = %d\n",pHero->level);
	fprintf(fsave,"#xp = %u\n",(unsigned int) pHero->curxp/2);
	fprintf(fsave,"#posx = %d\n",5);
	fprintf(fsave,"#posy = %d\n",5);
	fprintf(fsave,"#terrain = %d\n",1);
	fclose(fsave);

}

int herGetTerID(const Hero * pHero){
	return pHero->terid;
}



void herNewPosition(Hero * pHero,int x,int y ,int ter){
	pHero->terid = ter;
	pHero->x = x;
	pHero->y = y;
}

Spell * herGetSpells(const Hero * pHero){
	return pHero->tabspell;
}

int herGetNbSpells(const Hero * pHero){
	return pHero->nbspell;
}

void herSetMode(Hero * pHero,int mode){
	pHero->mode = mode;
}

int herGetDir(const Hero * pHero){
return pHero->direction;
}

float herGetSpeed(const Hero * pHero){
return pHero->speed;
}
void herSetCooldown(Hero * pHero,float interval){
pHero->cooldown -= interval;
}
void herSetCooldownAbs(Hero * pHero,float value){
pHero->cooldown = value;
}

Spell * herGetSpell(const Hero * pHero,int i){
return &(pHero->tabspell[i-1]);
}

int herGetIntel(const Hero * pHero){
return pHero->intel;
}
int herGetPower(const Hero * pHero){
return pHero->power;
}


void herTestRegression(){

	int temp;
	Hero pHero;

	printf("****** TEST HERO START ************ \n");

	herInit(&pHero);
	herInitContiue(&pHero);
	temp = herGetcurxp(&pHero);
	if(herGetcurxp(&pHero) < herGetxpmax(&pHero) - 5){
			herWinXp(&pHero, 5);
	}

	herFree(&pHero);

	herInit(&pHero);
	herInitContiue(&pHero);

	if(herGetcurxp(&pHero) == temp + 5){
		printf("Module travaille correctement...\n");
	}else{
		printf("Attention! Module erreur...\n");
	}

	herFree(&pHero);
	printf("****** TEST HERO END ************** \n");

}

